﻿using LitJson;
using System;
using UnityEngine;
using UnityWebSocket;
//SingletonManager: 继承MonoBehaviour的单例(也可以直接继承MonoBehaviour)
public partial class WebSocketClient : XObjBase
{
    public static WebSocketClient Instance;
    private DataHandle _dataHandle;
    protected override void Awake()
    {
        base.Awake();
        this.AwakeRender();
        Instance = this;

        //临时代码
        _dataHandle = new DataHandle();
        _dataHandle.OnRegist();
    }
    protected override void OnDestroy()
    {
        base.OnDestroy();
        Instance = null;

        //临时代码
        _dataHandle.OnUnRegist();
    }
    protected override void Start()
    {
        base.Start();
    }

    private IWebSocket socket;
    private string address;
    public WebSocketState state
    {
        get
        {
            return socket == null ? WebSocketState.Closed : socket.ReadyState;
        }
    }
    private Action connectCallBack;
    public void Connect(string vAddress, Action vConnectCallBack)
    {
        address = vAddress;
        socket = new WebSocket(address);
        socket.OnOpen += Socket_OnOpen;
        socket.OnMessage += Socket_OnMessage;
        socket.OnClose += Socket_OnClose;
        socket.OnError += Socket_OnError;
        AddLog(string.Format("Connecting..."));
        connectCallBack = vConnectCallBack;
        socket.ConnectAsync();
    }

    public void Close()
    {
        if (socket == null)
            return;
        AddLog(string.Format("Closing..."));
        socket.OnOpen -= Socket_OnOpen;
        socket.OnMessage -= Socket_OnMessage;
        socket.OnClose -= Socket_OnClose;
        socket.OnError -= Socket_OnError;
        socket.CloseAsync();
        socket = null;
    }

    public void SendSerialize(UnityEngine.UI.Button button, System.Object msg)
    {
        if (button != null)
            EnqueueButton(button);
        SendSerialize(msg);
    }
    public void SendSerialize(System.Object msg)
    {
        string msgName = msg.GetType().Name;
        string json_msg = JsonMapper.ToJson(msg);
        var mix = msgName + json_msg;
        Debug.Log("<color=red>Send:</color>" + mix);
        SendText(mix);
    }

    public void SendMsgName(UnityEngine.UI.Button button, string msg)
    {
        if (button != null)
            EnqueueButton(button);
        SendMsgName(msg);
    }

    public void SendMsgName(string msg)
    {
        var mix = msg + "{}";
        Debug.Log("<color=red>Send:</color>" + mix);
        SendText(mix);
    }

    public void SendText(string vSendText)
    {
        socket.SendAsync(vSendText);
    }

    public void SendBytes(string vSendText)
    {
        var bytes = System.Text.Encoding.UTF8.GetBytes(vSendText);
        socket.SendAsync(bytes);
    }
    private void Socket_OnOpen(object sender, OpenEventArgs e)
    {
        AddLog(string.Format("Connected: {0}", address));
        connectCallBack?.Invoke();
        connectCallBack = null;
    }

    private void Socket_OnMessage(object sender, MessageEventArgs e)
    {
        if (e.IsBinary)
        {
            AddLog(string.Format("<color=green>Receive Binary</color>:{0} len={1}", e.Data, e.RawData.Length));
        }
        else if (e.IsText)
        {
            //debug
            AddLog(string.Format("<color=green>Receive Text</color>:{0}", e.Data));
        }

        DequeueButtonAll();

        var startIndex = e.Data.IndexOf("{");
        if (startIndex < 0)
        {
            Debug.LogError("出错了startIndex:" + startIndex);
            return;
        }

        //获取消息名
        var msgName = e.Data.Substring(0, startIndex);

        //获取消息体
        var msg = e.Data.Substring(startIndex, e.Data.Length - startIndex);



        //反射解析
        Type type = Type.GetType(msgName);
        if (type == null)
        {
            Debug.LogError("can not find msg:" + msgName);
            return;
        }
        var protocol = JsonMapper.ToObject(msg, type);
        if (protocol == null)
        {
            Debug.LogError("convert to json error:" + msgName);
            return;
        }
        //发消息出去
        Facade.Instance.SendNetEvent(msgName, protocol);
    }

    private void Socket_OnClose(object sender, CloseEventArgs e)
    {
        AddLog(string.Format("Closed: StatusCode: {0}, Reason: {1}", e.StatusCode, e.Reason));
        ShowReconnect();
    }

    private void Socket_OnError(object sender, ErrorEventArgs e)
    {
        AddLog(string.Format("Error: {0}", e.Message));
        ShowReconnect();
    }

    private void OnApplicationQuit()
    {
        Close();
    }
    private void AddLog(string str)
    {
        Debug.Log(str);
    }

    [ContextMenu("TestClose")]
    private void TestClose()
    {
        Close();
        ShowReconnect();
    }

    private bool isShowReconnect = false;
    private void ShowReconnect()
    {
        if (!DataPlayer.Instance.IsLogined)
        {
            this.Close();
            UITips.Instance.Show("登录失败，请检查网络再尝试");
            return;
        }
        if (isShowReconnect) return;

        isShowReconnect = true;
        UIDialog.Instance.Show(XLocalization.Get("提示"), XLocalization.Get("网络已断开，是否重连？"), ()=> {
            this.Close();
            isShowReconnect = false;
            //重连逻辑
            this.Connect(address, ReconnectCallBack);
        }, () => {
#if UNITY_EDITOR
            UnityEditor.EditorApplication.isPlaying = false;
#else
            UITips.Instance.Show("游戏异常，请重启游戏");
#endif
        });
    }

    private void ReconnectCallBack()
    {
        var req = new reconnect();
        req.user = DataPlayer.Instance.cacheUser;
        req.psw = DataPlayer.Instance.cachePsw;
        WebSocketClient.Instance.SendSerialize(req);
    }
}

public class Person
{
    public int ret { get; set; }
    public string reason { get; set; }

}
/*
 using LitJson;
using System;

public class Person
{
    // C# 3.0 auto-implemented properties
    public string   Name     { get; set; }
    public int      Age      { get; set; }
    public DateTime Birthday { get; set; }
}

public class JsonSample
{
    public static void Main()
    {
        PersonToJson();
        JsonToPerson();
    }

    public static void PersonToJson()
    {
        Person bill = new Person();

        bill.Name = "William Shakespeare";
        bill.Age  = 51;
        bill.Birthday = new DateTime(1564, 4, 26);

        string json_bill = JsonMapper.ToJson(bill);

        Console.WriteLine(json_bill);
    }

    public static void JsonToPerson()
    {
        string json = @"
            {
                ""Name""     : ""Thomas More"",
                ""Age""      : 57,
                ""Birthday"" : ""02/07/1478 00:00:00""
            }";

        Person thomas = JsonMapper.ToObject<Person>(json);

        Console.WriteLine("Thomas' age: {0}", thomas.Age);
    }
}
 */